72 - Navigation

image-20251114161010760

 

image-20251114161046437

因为react navigation对不使用expo的应用也能行,所以接下来学习react navigation。文档:https://reactnavigation.org/

1、创建项目npx create-expo-app@latest RNNavigation --template blank,这个命令会创建一个没有expo router的项目,方便我们学习react navigation。

2、安装react navigation:npm install @react-navigation/native

3、安装依赖:npx expo install react-native-screens react-native-safe-area-context

4、在入口文件(App.js / App.tsx)启用 NavigationContainer

接下来,就可以在App里面写导航相关的代码了。

73 - Stack Navigation

React Navigation 的 Navigator 大概分成四大类:

  1. Stack Navigator(堆栈导航)
  2. Tab Navigator(底部/顶部 Tab 导航)
  3. Drawer Navigator(侧边抽屉导航)
  4. Material 系导航(Tab/Top/Bottom)

1️⃣ Stack Navigator(最常用、页面跳转)

就像浏览器前进/后退、App 页面跳转一样:

每个页面像“一张纸”压在另一张上面。

⭐ 特点

⭐ 适合场景

⭐ 典型用法


2️⃣ Tab Navigator(底部导航 ⁄ 顶部导航)

底部菜单栏:

用户点击 Tab 切换页面。

⭐ 特点

⭐ 适合场景

⭐ 用法


3️⃣ Drawer Navigator(侧边抽屉导航)

左侧滑出(或右侧)的菜单:

⭐ 特点

⭐ 适合场景

⭐ 用法


4️⃣ Material 系导航(根据 UI 规范设计)

如果你想做更“安卓风格”的 UI,可以用:

🔹 Material Bottom Tabs

🔹 Material Top Tabs

⭐ 特点

⭐ 适合场景


🧩 那这些 Navigator 应该怎么组合?

几乎所有大型 RN 应用结构都是:

也就是说:

⭐ 顶层是 Stack

因为你需要处理:

⭐ Tabs 放在 Stack 里

因为 Tab 是“主骨架”。

⭐ Drawer 也通常放在 Stack 里

因为 Drawer 控制行为通常独立。


🎯 什么时候选哪种?

📌 想“页面跳转” → Stack

📌 想“底部切换功能” → Tabs

📌 想“滑出菜单” → Drawer

📌 想“安卓风格 Tab(顶部/底部)” → Material 系 Navigator


🔥 最常见的实际用法(强烈推荐)

99% 项目这样写:

这是大厂 RN 项目的标准结构。

Stack Navigator(堆栈导航)模拟的是 iOS / Android 原生的页面跳转方式

image-20251114190000230

 

Stack Navigation有两种,一种是Stack Navigator,另一种是Native Stack Navigator。课程中老师只讲解Native Stack Navigator,参考文档:https://reactnavigation.org/docs/native-stack-navigator

安装依赖:npm install @react-navigation/native-stack

image-20251114190050278

🧱 Stack Navigator 组成部分

一个 Stack Navigator 有三个核心角色:

  1. NavigationContainer:导航容器(必须包裹整个导航树)
  2. createNativeStackNavigator():创建 Stack 对象
  3. Stack.Screen:注册页面

在入口文件(App.js / App.tsx)启用NavigationContainer

Stack.Screen核心属性:

属性类型描述
namestring必需。 为此屏幕定义的唯一路由名称。您在导航时(例如使用 navigation.navigate('Home'))将使用此名称。
componentReact Component必需。 当此屏幕成为焦点时将渲染的 React 组件。此组件会自动接收 navigationroute props。
optionsobject非必需。用于配置此屏幕的外观和行为,例如导航栏的标题、样式、按钮等。

options属性

选项 (常用)类型描述
titlestring设置导航栏的标题文字。
headerShownboolean设置是否显示导航栏。默认是 true
headerStyleobject设置导航栏(头部)的样式,例如背景颜色。
headerTitleStyleobject设置导航栏标题文本的样式。
headerTintColorstring设置导航栏按钮和标题的颜色。
headerRight(props) => React Node渲染导航栏右侧的组件(例如按钮)。
headerLeft(props) => React Node渲染导航栏左侧的组件。
presentationstring仅在 @react-navigation/native-stack 中:控制屏幕出现的方式(如 modalcardtransparentModal 等)。

定义页面

定义两个相似的页面HomeScreen.jsAboutScreen.js,这里只展示HomeScreen的代码。

在App.js中引入并使用具体页面

查看效果:

img

可以看到,只展示了HomeScreen页面,那页面之间怎么跳转呢?下节课会讲到。

74 - Navigation between Screens

可以通过navigation prop或者useNavigation()这个hook来实现页面之间的跳转。

navigation prop

在 Stack Navigator 中,只要一个组件是作为 Stack.Screencomponent 属性注册的,它就会自动接收到 navigationroute 这两个 props。

使用navigation的navigate方法,进行跳转。

image-20251114193317083

可以看到,从Home跳转到了About页面,同时上面还有一个返回按钮。

useNavigation

image-20251114193554609

两种跳转方式在哪些情况下使用

特性navigation PropuseNavigation() Hook
获取方式作为参数 { navigation, route } 传入组件。通过 const navigation = useNavigation(); 调用。
适用组件屏幕组件 (Screen Component):即直接在 <Stack.Screen component={...}> 中注册的组件。任何组件:屏幕组件或嵌套在屏幕内部的子组件 (Child Component)
可访问性只能在作为屏幕注册的组件内部访问。可以在组件树中的任何地方访问(只要它被包裹在导航容器内)。
代码简洁度略微分散,需要解构 props独立且清晰,但在非屏幕组件中是唯一选择。
推荐原则如果组件是直接注册的屏幕,这是标准方式,性能开销最小。如果组件是通用或嵌套的子组件,并且不知道/不关心它是否是屏幕。

75 - Passing Data between Screens

在Screens之间传递数据。

路由参数 (Route Params)

在调用 navigation.navigate()navigation.push() 时,将数据作为第二个参数的对象传递。在目标屏幕组件中,通过 route.params 访问数据。

image-20251114194523328

image-20251114194431961

效果:

怎么在About里面向Home传递数据呢?如果是手动触发,那么还是可以在navigation.navigate的第二个参数里面传递数据,然后Home里面使用route来接收。

但如果是nav栏的返回按钮触发的返回呢?这个还能生效吗?估计不能,这时候就需要使用第三方状态管理库了。

76 - Stack Navigation Options

Stack.Screen的options属性:

选项 (常用)类型描述
titlestring设置导航栏的标题文字。
headerShownboolean设置是否显示导航栏。默认是 true
headerStyleobject设置导航栏(头部)的样式,例如背景颜色。
headerTitleStyleobject设置导航栏标题文本的样式。
headerTintColorstring设置导航栏按钮和标题的颜色。
headerRight(props) => React Node渲染导航栏右侧的组件(例如按钮)。
headerLeft(props) => React Node渲染导航栏左侧的组件。
presentationstring仅在 @react-navigation/native-stack 中:控制屏幕出现的方式(如 modalcardtransparentModal 等)。
contentStyleobject设置屏幕的背景颜色

image-20251114201309474

效果:

如果想设置所有页面的nav和content的样式,可以在Stack.Navigator上设置screenOptions属性:

image-20251114201345368

可以看到About页面并没有设置nav和content的样式,也成功有了样式。

77 - Dynamic Stack Navigator Options

方式 1:使用 options 属性的函数形式 (推荐)

Stack.Screenoptions 属性中传入一个函数,该函数会接收到包含当前路由信息的对象。

可以看到,跳转到About页面时,nav栏的标题变为了传递的参数。

方式 2:使用 navigation.setOptions() 方法 (最灵活)

当您需要根据屏幕内部的异步数据或用户交互(例如,用户在表单中输入内容、数据加载完成)来改变导航栏时,您需要在组件内部调用 navigation.setOptions() 方法。

image-20251114203459393

78 - Drawer Navigation

接下来关于导航的内容,老师讲的都非常快,很多属性都是一笔带过,这个了解一下即可,现在流行expo router,就使用它即可。

Drawer Navigation 是 React Native 中非常常用的一种导航模式,通常用于提供应用主功能区域的入口,或放置不太常用的设置和配置项。它以一个从屏幕边缘滑入(通常是左侧)的侧边面板的形式呈现。参考文档:https://reactnavigation.org/docs/drawer-navigator

image-20251114203634976

安装依赖:npm install @react-navigation/drawernpx expo install react-native-gesture-handler react-native-reanimated react-native-worklets

将原来的App.js改为AppStack.js,然后新建一个App.js文件。

创建两个相似的页面:

效果:

79 - Drawer Navigation Options

屏幕导航栏配置 (Header/Screen Options)

属性名类型描述
titlestring设置 Header 中央显示的标题文本。
headerShownboolean是否显示 Header(导航栏)。默认 true
headerStyleobjectHeader 容器的样式,常用于设置 backgroundColor
headerTintColorstringHeader 上的按钮和标题的颜色。
headerLeft(props) => React Node渲染 Header 左侧的自定义组件。在 Drawer 导航器中,通常这里会放置抽屉开关按钮
headerRight(props) => React Node渲染 Header 右侧的自定义组件。
headerTitleStyleobject标题文本的样式。

抽屉菜单项配置 (Drawer Item Appearance)

属性名类型默认值描述
drawerLabelstring(props) => React Node路由的 name在抽屉菜单中显示的文本标签。如果为函数,可以返回自定义组件。
drawerIcon(props) => React Nodeundefined在抽屉菜单项旁边显示的图标组件。接收 { focused, color, size } 属性。
drawerItemStyleobjectundefined应用于抽屉菜单项整个容器的样式。
drawerLabelStyleobjectundefined应用于抽屉菜单项文本标签的样式。
drawerActiveTintColorstring平台默认色抽屉菜单项处于 活动/焦点 状态时,图标和文本的颜色。
drawerInactiveTintColorstring平台默认色抽屉菜单项处于 非活动 状态时,图标和文本的颜色。
drawerActiveBackgroundColorstring透明抽屉菜单项处于 活动/焦点 状态时,背景的颜色。
drawerInactiveBackgroundColorstring透明抽屉菜单项处于 非活动 状态时,背景的颜色。
swipeEnabledbooleantrue是否允许通过屏幕边缘手势滑动来打开/关闭抽屉。

80 - Tab Navigation

image-20251115091042522

安装npm install @react-navigation/bottom-tabs

将App.js文件名改为AppDrawer.js,然后创建App.js文件。

 

81 - Tab Navigation Options

标签栏条目配置 (Tab Bar Item Appearance)

属性名类型适用描述
tabBarLabelstring(props) => React NodeBoth标签栏中显示的文本标签。如果为函数,可实现动态渲染或自定义组件。
tabBarIcon(props) => React NodeBoth标签栏中显示的图标组件。接收 { focused, color, size } 属性,用于根据焦点状态切换图标。
tabBarBadgestringnumberbooleanBottom在标签栏图标上方显示的小红点或数字(如未读消息数量)。
tabBarAccessibilityLabelstringBoth供屏幕阅读器使用的可访问性标签。
tabBarTestIDstringBoth用于测试的 ID。
tabBarButton(props) => React NodeBoth用于完全自定义整个标签项组件(包括容器和点击行为)。
tabBarShowLabelbooleanBoth是否显示标签文本。如果为 false,则只显示图标。
tabBarActiveTintColorstringBoth标签项处于 活动/焦点 状态时,图标和文本的颜色。
tabBarInactiveTintColorstringBoth标签项处于 非活动 状态时,图标和文本的颜色。

屏幕/导航栏配置 (Screen & Header Options)

属性名类型适用描述
titlestringBoth设置 Header 中央显示的标题文本。
headerShownbooleanBoth是否显示 Header(导航栏)。如果 Tab 嵌套在 Stack 中,通常需要在 Stack 导航器中配置。
lazybooleanBottom仅 Bottom Tab。 是否延迟加载此屏幕组件,直到用户第一次访问它。默认 true
unmountOnBlurbooleanBoth屏幕失去焦点时是否卸载(Unmount)该组件,下次访问时重新渲染。
freezeOnBlurbooleanBoth屏幕失去焦点时是否停止渲染和事件处理,以优化性能。
contentStyleobjectBoth设置屏幕内容区域的样式(例如背景色)。

82 - Nesting Navigators

image-20251115093430958

核心原则:

Stack Navigator 应该作为容器,包裹住 Tab Navigator 或 Drawer Navigator。

这是因为 Tab 和 Drawer 导航器通常代表应用的主要结构,而 Stack Navigator 负责处理每个主要部分的历史记录屏幕之间的过渡效果

Tab Navigator 作为应用主框架

这是最常见的模式。应用底部有一个固定的 Tab Bar,每个 Tab 内部管理自己的导航历史。

结构图

实现方式:

  1. 定义 Tab Navigator: 创建主 Tab 导航器,并在每个 Tab.Screencomponent 中,嵌套一个独立的 Stack Navigator。
  2. 定义 Stack Navigators: 每个 Tab 对应的 Stack 负责管理该 Tab 内部的页面跳转历史(例如:Home Stack 负责 HomeHomeDetails 的跳转)。
  3. 定义 Root Stack: 最外层通常再用一个 Stack Navigator 来处理全局模态框(Modal)或身份验证流程(如 Login、Signup)。

示例代码:

经验法则:

  1. Stack 是历史记录和过渡动画的管理者。 任何需要显示 Header、处理页面 push/pop 或全局模态框的地方,都需要 Stack 作为父级。
  2. Tab 和 Drawer 是应用布局的管理者。 它们定义了屏幕之间的同级切换关系,通常被 Stack 包裹。